/********************************************************
 * This file contains a simple hash table implementation
 ********************************************************/

#ifndef __HASH_H
#define __HASH_H

#ifndef __VECTOR_H
# error "Please include vector.h before hash.h"
#endif

#ifndef __EXMALLOC_H
# error "Please include exmalloc.h before hash.h"
#endif

struct hsh_kv_pair {
    struct list_head list;
    union {
        void *v_value;
        int   i_value;
    } value;
    unsigned int length;
    char key[0];
};

struct hash_table {
    unsigned int size;
    void (*_free)(void*);
    struct vector kv_pairs[0];
};

/**
 * hsh_alloc - get a new hash instance
 * @hsh: double pointer to hash_table struct
 * @_free: this function will get called to free the value member
 * @size: the size of the hash table (should be a prime number)
 */
inline void hsh_alloc(struct hash_table **hsh, void (*_free)(void*), unsigned int size);

/**
 * hsh_free - free all items in the hash and then free the hash_table
 * @hsh: double pointer to hash_table struct
 * 
 * This function will also free all value members if provided a custom free function
 */
inline void hsh_free(struct hash_table **hsh);

/**
 * hsh_add_type - add a new hash entry with a generic value
 * @hsh: pointer to hash_table struct
 * @key: the string key for the new value
 * @length: key size
 * @value: the value to associate with the key
 */
#define create_hsh_add(func, type)                                      \
inline void func(struct hash_table *hsh, void *key, unsigned int length, type value);

create_hsh_add(hsh_add_void, void*)
create_hsh_add(hsh_add_int, int)

/**
 * hsh_get_type - get the type value associated with a given key
 * @hsh: pointer to hash_table struct
 * @key: the string key
 * @length: key size
 * @value: pointer to the type value to store the result
 */
#define create_hsh_get(func, type)                                      \
inline int func(struct hash_table *hsh, void *key, unsigned int length, type *value);

create_hsh_get(hsh_get_void, void*)
create_hsh_get(hsh_get_int, int)

/**
 * hsh_delete_type - delete the given key and return a pointer to the type value associated with the given key
 * @hsh: pointer to hash_table struct
 * @key: the string key
 * @length: key size
 * @value: pointer to the type value to store the result
 */
#define create_hsh_delete(func, type)                                   \
inline int func(struct hash_table *hsh, void *key, unsigned int length, type *value);

create_hsh_delete(hsh_delete_void, void*)
create_hsh_delete(hsh_delete_int, int)

/**
 * hsh_begin - position the hash before the first item
 * @hsh: pointer to hash_table struct
 * @n: internally used member of type integer
 * @pair: internally used member of type struct hsh_kv_pair
 */
inline void hsh_begin(struct hash_table *hsh, int *n, struct hsh_kv_pair **pair);

/**
 * hsh_next_type - get the next type value in the hash_table struct
 * @hsh: pointer to hash_table struct
 * @n: internally used member of type integer
 * @pair: internally used member of type struct hsh_kv_pair
 * @value: pointer to type value for storing the result
 */
#define create_hsh_next(func, type)                                     \
inline int func(struct hash_table *hsh, int *n, struct hsh_kv_pair **pair, type *value);

create_hsh_next(hsh_next_void, void*)
create_hsh_next(hsh_next_int, int)

#endif /* __HASH_H */
